#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_mac.h"
#include "esp_netif.h"
#include <sys/socket.h>
#include "lwip/err.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>

#include "driver/i2s_std.h"
#include "driver/i2s_common.h"
#include "driver/i2s_types.h"

#include "driver/gpio.h"
#include "iot_button.h"
#include "button_gpio.h"

// ESP32S3-N16R8
#define MAX_LRC GPIO_NUM_39
#define MAX_BCLK GPIO_NUM_38
#define MAX_DIN GPIO_NUM_14
// 麦克风的引脚
#define INMP_SD GPIO_NUM_2
#define INMP_SCK GPIO_NUM_1 //GPIO_NUM_5 // MAX_BCLK = INMP_SCK
#define INMP_WS GPIO_NUM_3//GPIO_NUM_4 // MAX_LRC = INMP_WS

// 配置扬声器/麦克风的采样率
#define SAMPLE_RATE 44100

// i2s_common: dma frame num is out of dma buffer size, limited to 1023
#define DMA_FRAME_NUM 511
// TODO 音乐是16bit，单声道。但是麦克风必须这么配置！要不没声音，或者全是杂音！
#define SLOT_NUM I2S_SLOT_MODE_STEREO // 双声道
#define SLOT_BIT_WIDTH I2S_DATA_BIT_WIDTH_32BIT // 16bit


// 要连接的WIFI
#define ESP_WIFI_STA_SSID "Aiiot"
#define ESP_WIFI_STA_PASSWD "1234567890"

// 目标服务器地址端口
#define UDP_SREVER_ADDR "192.168.0.255"
#define UDP_SREVER_PORT 8080

#define BOOT_BUTTON_NUM         0
#define BUTTON_ACTIVE_LEVEL     0

// https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32/api-reference/peripherals/i2s.html#id13
// 这里的一帧是指一个 WS 周期内的所有采样数据。因此， dma_buffer_size = dma_frame_num * slot_num * slot_bit_width / 8
#define DMA_BUF_SIZE 1400

int button_is_pressed = 0;

// 音频buffer
uint8_t use_buffer[DMA_BUF_SIZE] = {0};

uint8_t use_buffer2[DMA_BUF_SIZE] = {0};

i2s_chan_handle_t tx_handle;
i2s_chan_handle_t rx_handle;

extern const uint8_t music_pcm_start[] asm("_binary_canon_pcm_start");
extern const uint8_t music_pcm_end[]   asm("_binary_canon_pcm_end");

const char *button_event_table[] = {
    "BUTTON_PRESS_DOWN",
    "BUTTON_PRESS_UP",
    "BUTTON_PRESS_REPEAT",
    "BUTTON_PRESS_REPEAT_DONE",
    "BUTTON_SINGLE_CLICK",
    "BUTTON_DOUBLE_CLICK",
    "BUTTON_MULTIPLE_CLICK",
    "BUTTON_LONG_PRESS_START",
    "BUTTON_LONG_PRESS_HOLD",
    "BUTTON_LONG_PRESS_UP",
};


static void button_event_up(void *arg, void *data)
{
    char *TAG = "button_event_cb";
    iot_button_print_event((button_handle_t)arg);
    
    button_is_pressed = 0;
}

static void button_event_down(void *arg, void *data)
{
    char *TAG = "button_event_cb";
    iot_button_print_event((button_handle_t)arg);
    
    button_is_pressed = 1;
}

void button_init(uint32_t button_num)
{
    button_config_t btn_cfg = {0};
    button_gpio_config_t gpio_cfg = {
        .gpio_num = button_num,
        .active_level = BUTTON_ACTIVE_LEVEL,
        .enable_power_save = true,
    };

    button_handle_t btn;
    esp_err_t ret = iot_button_new_gpio_device(&btn_cfg, &gpio_cfg, &btn);
    assert(ret == ESP_OK);

    ret = iot_button_register_cb(btn, BUTTON_PRESS_DOWN, NULL, button_event_down, NULL);
    ret |= iot_button_register_cb(btn, BUTTON_PRESS_UP, NULL, button_event_up, NULL);

    ESP_ERROR_CHECK(ret);
}

// MAX98357A 扬声器 写数据 

void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
	static uint8_t connect_count = 0;
	// WIFI 启动成功
	if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
	{
		ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START");
		ESP_ERROR_CHECK(esp_wifi_connect());
	}
	// WIFI 连接失败
	if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
	{
		ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED");
		connect_count++;
		if (connect_count < 6)
		{
			vTaskDelay(1000 / portTICK_PERIOD_MS);
			ESP_ERROR_CHECK(esp_wifi_connect());
		}
		else
		{
			ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times");
		}
	}
	// WIFI 连接成功(获取到了IP)
	if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
	{
		ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP");
		ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data;
		ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip));
	}
}

static void i2s_tx_init() {
    // 用 I2S1 作为主机（Master）初始化一个 I2S 通道，用于音频数据的发送（播放）。
    i2s_chan_config_t tx_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
    tx_config.dma_frame_num = DMA_FRAME_NUM;
    
    // ⚠️
    ESP_ERROR_CHECK(i2s_new_channel(&tx_config, &tx_handle, NULL));

    i2s_std_config_t tx_std_config = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
        .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(SLOT_BIT_WIDTH, SLOT_NUM),
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED,
            .din = I2S_GPIO_UNUSED,
            .bclk = MAX_BCLK,
            .ws = MAX_LRC,
            // ⚠️
            .dout = MAX_DIN,
            .invert_flags = {
                .bclk_inv = false,
                .ws_inv = false,
                .mclk_inv = false,
            }
        },
    };

    ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &tx_std_config));
    ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
}

// INMP441 麦克风 读数据
static void i2s_rx_init() {
    // i2s_chan_config_t rx_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER);
    i2s_chan_config_t rx_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);

    rx_config.dma_frame_num = DMA_FRAME_NUM;

    // ⚠️
    ESP_ERROR_CHECK(i2s_new_channel(&rx_config, NULL, &rx_handle));
    // ESP_ERROR_CHECK(i2s_new_channel(&rx_config, &tx_handle, &rx_handle));
    i2s_std_slot_config_t rx_slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(SLOT_BIT_WIDTH, SLOT_NUM);
    // 不加听不到人声
    rx_slot_cfg.bit_shift = true; // 使能位移
    i2s_std_config_t rx_std_config = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
        .slot_cfg = rx_slot_cfg, //I2S_STD_MSB_SLOT_DEFAULT_CONFIG(SLOT_BIT_WIDTH, SLOT_NUM),
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED,
            // ⚠️
            .din = INMP_SD,
            .bclk = INMP_SCK,
            .ws = INMP_WS,
            .dout = I2S_GPIO_UNUSED,
            .invert_flags = {
                .bclk_inv = false,
                .ws_inv = false,
                .mclk_inv = false,
            }
        },
    };

    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &rx_std_config));
    ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
}

static void mic_2_speaker(void *arg)
{
    size_t bytes = 0;
    char *TAG = "mic_2_speaker";
    
    ESP_LOGI(TAG, "开始麦克风到扬声器传输");
    vTaskDelay(pdMS_TO_TICKS(500));

    while (1) {
        esp_err_t read_ret = i2s_channel_read(rx_handle, use_buffer, DMA_BUF_SIZE, &bytes, 1000);
        
        if(read_ret == ESP_OK && bytes > 0) {
            esp_err_t write_ret = i2s_channel_write(tx_handle, use_buffer, DMA_BUF_SIZE, &bytes, 1000);
            if (write_ret != ESP_OK) {
                ESP_LOGE(TAG, "写入扬声器失败: %s", esp_err_to_name(write_ret));
            }
        } else {
            ESP_LOGI(TAG, "读取麦克风失败: %s, 字节数: %d", esp_err_to_name(read_ret), bytes);
        }
        
        vTaskDelay(pdMS_TO_TICKS(5));
    }
}

static void udp_client_task(void *pvParameters)
{
    size_t bytes = 0;
    char *TAG = "mic_2_speaker";
    
    ESP_LOGI(TAG, "开始麦克风到扬声器传输");
    vTaskDelay(pdMS_TO_TICKS(500));

	// 等待wifi连接成功(暂时这样处理)
	vTaskDelay(5000 / portTICK_PERIOD_MS);
	ESP_LOGI("udp_client_task", "udp_client_task start");

	// 创建socket
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) // 创建失败返回-1
	{
		ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
		return;
	}

	// 设置服务器(IPV4)
	struct sockaddr_in server_config;
	server_config.sin_addr.s_addr = inet_addr(UDP_SREVER_ADDR);
	server_config.sin_family = AF_INET;
	server_config.sin_port = htons(UDP_SREVER_PORT); // 宏htons 用于将主机的无符号短整型数据转换成网络字节顺序(小端转大端)


	char rx_buffer[1024];
	// 接收数据,并发回
	while(1)
	{
		if(button_is_pressed == 1){
			esp_err_t read_ret = i2s_channel_read(rx_handle, use_buffer, DMA_BUF_SIZE, &bytes, 1000);
        
			if(read_ret == ESP_OK && bytes > 0) {
				// esp_err_t write_ret = i2s_channel_write(tx_handle, use_buffer, DMA_BUF_SIZE, &bytes, 1000);
				// if (write_ret != ESP_OK) {
				//     ESP_LOGE(TAG, "写入扬声器失败: %s", esp_err_to_name(write_ret));
				// }

				int err = sendto(sock, use_buffer, bytes, 0, (struct sockaddr *)&server_config, sizeof(server_config));
				if (err < 0)
				{
					ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
					// close(sock);
				}else{
					// ESP_LOGI(TAG, "发送成功");
				}
			} else {
				ESP_LOGI(TAG, "读取麦克风失败: %s, 字节数: %d", esp_err_to_name(read_ret), bytes);
			}
		}
        
        
        vTaskDelay(pdMS_TO_TICKS(5));
	}
	// 关闭socket
	close(sock);
	vTaskDelete(NULL);
}


static void udp_server_task(void *pvParameters)
{
    size_t bytes = 0;
    char *TAG = "receiver";
    
    ESP_LOGI(TAG, "开始麦克风到扬声器传输");
	// 等待wifi连接成功(暂时这样处理)
	vTaskDelay(5000 / portTICK_PERIOD_MS);
	ESP_LOGI("udp_server_task", "udp_server_task start");

	// 创建socket
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) // 创建失败返回-1
	{
		ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
		return;
	}

	// 设置服务器(IPV4)
	struct sockaddr_in server_config;
	server_config.sin_addr.s_addr = htonl(INADDR_ANY);
	server_config.sin_family = AF_INET;
	server_config.sin_port = htons(UDP_SREVER_PORT); // 宏htons 用于将主机的无符号短整型数据转换成网络字节顺序(小端转大端)
	
	// 绑定端口
	int err = bind(sock, (struct sockaddr *)&server_config, sizeof(server_config));
	if (err < 0)
	{
		ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
	}
	ESP_LOGI(TAG, "Socket bound, port %d", UDP_SREVER_PORT);

	// char rx_buffer[1024];
	// 接收数据,并发回
	while(1)
	{
		if(button_is_pressed == 0){
			// 清空缓存
			memset(use_buffer2, 0, sizeof(use_buffer2));
			// 接收数据

			struct sockaddr_in source_addr;
			socklen_t socklen = sizeof(source_addr);
			size_t len = recvfrom(sock, use_buffer2, sizeof(use_buffer2) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
			if (len < 0)
			{
				ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);
				break;
			}
			else
			{
				// 打印接收到的数据
				ESP_LOGI(TAG, "Received %d bytes: %d", len, use_buffer2[50]);
				esp_err_t write_ret = i2s_channel_write(tx_handle, use_buffer2, DMA_BUF_SIZE, &len, 1000);
				if (write_ret != ESP_OK) {
					ESP_LOGE(TAG, "写入扬声器失败: %s", esp_err_to_name(write_ret));
				}
			}
		}
		
	}
	// 关闭socket
	close(sock);
	vTaskDelete(NULL);
}


static void virtual_button_task(void *pvParameters)
{
    size_t bytes = 0;
    char *TAG = "receiver";
    
    ESP_LOGI(TAG, "开始麦克风到扬声器传输");
	// 等待wifi连接成功(暂时这样处理)
	vTaskDelay(5000 / portTICK_PERIOD_MS);
	ESP_LOGI("udp_server_task", "udp_server_task start");

	// 创建socket
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) // 创建失败返回-1
	{
		ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
		return;
	}

	// 设置服务器(IPV4)
	struct sockaddr_in server_config;
	server_config.sin_addr.s_addr = htonl(INADDR_ANY);
	server_config.sin_family = AF_INET;
	server_config.sin_port = htons(8081); // 宏htons 用于将主机的无符号短整型数据转换成网络字节顺序(小端转大端)
	
	// 绑定端口
	int err = bind(sock, (struct sockaddr *)&server_config, sizeof(server_config));
	if (err < 0)
	{
		ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
	}
	ESP_LOGI(TAG, "Socket bound, port %d", UDP_SREVER_PORT);

	uint8_t rx_buffer[2];
	// 接收数据,并发回
	while(1)
	{
		// 清空缓存
		memset(rx_buffer, 0, sizeof(rx_buffer));
		// 接收数据

		struct sockaddr_in source_addr;
		socklen_t socklen = sizeof(source_addr);
		size_t len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
		if (len < 0)
		{
			ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);
			break;
		}
		else
		{
			// 打印接收到的数据
			ESP_LOGI(TAG, "Received %d bytes: %d", len, rx_buffer[0]);
            if(rx_buffer[0] == 0x01){
				button_is_pressed = 1;
            }else{
				button_is_pressed = 0;
            }
		}
	}
	// 关闭socket
	close(sock);
	vTaskDelete(NULL);
}



// 以双工方式初始化I2S通道
void i2s_init() {
    // 使用单个I2S控制器
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
    chan_cfg.dma_frame_num = DMA_FRAME_NUM;
    
    // 同时创建TX和RX句柄
    ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
    
    // 扬声器配置 (TX)
    i2s_std_config_t tx_std_config = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
        .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(SLOT_BIT_WIDTH, SLOT_NUM),
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED,
            .din = I2S_GPIO_UNUSED,
            .bclk = MAX_BCLK,
            .ws = MAX_LRC,
            // ⚠️
            .dout = MAX_DIN,
            .invert_flags = {
                .bclk_inv = false,
                .ws_inv = false,
                .mclk_inv = false,
            }
        },
    };
    
    // 麦克风配置 (RX)，使用共享时钟信号
    i2s_std_slot_config_t mic_std_slot_config = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(SLOT_BIT_WIDTH, SLOT_NUM);

    mic_std_slot_config.bit_shift = true; // 使能位移

    i2s_std_config_t rx_std_config = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
        .slot_cfg = mic_std_slot_config,
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED,
            .dout = I2S_GPIO_UNUSED,
            .bclk = INMP_SCK,
            .ws = INMP_WS,
            // ⚠️
            .din = INMP_SD,
            .invert_flags = {
                .bclk_inv = false,
                .ws_inv = false,
                .mclk_inv = false,
            }
        },
    };
    
    // 初始化并启用TX和RX通道
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &tx_std_config));
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &rx_std_config));
    ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
    ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
}


// wifi初始化
static void wifi_sta_init(void)
{
	ESP_ERROR_CHECK(esp_netif_init());

	// 注册事件(wifi启动成功)
	ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL));
	// 注册事件(wifi连接失败)
	ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL));
	// 注册事件(wifi连接失败)
	ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL));

	// 初始化STA设备
	esp_netif_create_default_wifi_sta();

	/*Initialize WiFi */
	wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
	// WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏

	ESP_ERROR_CHECK(esp_wifi_init(&cfg));

	//----------------配置阶段-------------------
	// 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源，如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等，这个 WiFi 也启动 WiFi 任务。必须先调用此API，然后才能调用所有其他WiFi API)
	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));

	// STA详细配置
	wifi_config_t sta_config = {
		.sta = {
			.ssid = ESP_WIFI_STA_SSID,
			.password = ESP_WIFI_STA_PASSWD,
			.bssid_set = false,
		},
	};
	ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config));

	//----------------启动阶段-------------------
	ESP_ERROR_CHECK(esp_wifi_start());

	//----------------配置省电模式-------------------
	// 不省电(数据传输会更快)
	ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
}
void app_main(void)
{
    // Initialize NVS
	esp_err_t ret = nvs_flash_init();
	if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
	{
		ESP_ERROR_CHECK(nvs_flash_erase());
		ret = nvs_flash_init();
	}
	ESP_ERROR_CHECK(ret);

	// 创建默认事件循环
	ESP_ERROR_CHECK(esp_event_loop_create_default());

	// 配置启动WIFI
	wifi_sta_init();


    i2s_init();
    // xTaskCreate(mic_2_speaker, "mic_2_speaker", 4096, NULL, 5, NULL);

    // 创建TCP客户端任务
	xTaskCreate(udp_client_task, "udp_client_task", 4096, NULL, 5, NULL);

    xTaskCreate(udp_server_task, "udp_server_task", 4096, NULL, 5, NULL);

	// xTaskCreate(virtual_button_task, "virtual_button_task", 4096, NULL, 5, NULL);
	button_init(BOOT_BUTTON_NUM);
}